<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>js无限轮播简单版实现</title>
  <style type="text/css">
    * { margin: 0; padding: 0; box-sizing: border-box;}
    .container { overflow: hidden; margin: 100px; position: relative; }
    .slide-box { display: flex; position: relative; }
    .slide-item { display: flex; align-items: center; justify-content: center; font-size: 48px; color: #fff;}
    .slide-item.red { background-color: red; }
    .slide-item.orange { background-color: orange; }
    .slide-item.blue { background-color: blue; }
    .slide-item.purple { background-color: purple; }
    .slide-item.pink { background-color: pink; }

    .btns a {
      display: none;
      width: 40px;
      height: 40px;
      line-height: 40px;
      background: rgba(0,0,0,0.3);
      color: #fff;
      position: absolute;
      cursor: pointer;
      top: 50%;
      margin-top: -20px;
      text-align: center;
    }
    .btns a.pre {
      left: 10px;
    }
    .btns a.next {
      right: 10px;
    }
    .btns a:hover {
      background: rgba(0,0,0,0.7);
    }
    .container:hover .btns a {
      display: block;
    }

    .dots {
      position: absolute;
      bottom: 20px;
      width: 100%;
      text-align: center;
      font-size: 0;
    }
    .dots span {
      display: inline-block;
      width: 10px;
      height: 10px;
      background: #ccc;
      border: 2px solid #999;
      border-radius: 50%;
      margin: 4px;
      cursor: pointer;
    }
    .dots span.on {
      background: #333;
      border-color: #fff;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="slide-box">
      <div class="slide-item red">1</div>
      <div class="slide-item orange">2</div>
      <div class="slide-item blue">3</div>
      <div class="slide-item purple">4</div>
      <div class="slide-item pink">5</div>
    </div>
    <div class="btns">
      <a class="pre">pre</a>
      <a class="next">next</a>
    </div>
    <div class="dots">
      <!-- <span class="on"></span>
      <span></span>
      <span></span>
      <span></span>
      <span></span> -->
    </div>
  </div>
  <script>
    /*
      t 切换一屏需要的时间
      interval 屏切换时分多少次来修改left的值（使效果看起来像动画，不那么生硬）
      itemW 每一屏的宽度
      itemH 每一屏的高度
      animating 屏正在切换动画中
      timer 自动轮播的定时器
    */
    let t = 400, interval = 20, itemW = 500, itemH = 300, animating = false, timer = null,
    container = document.querySelector('.container'),  // 最外层容器
    slideBox = document.querySelector('.slide-box'), // 滚动项的外包裹层
    slideItems = slideBox.children
    let dots = document.querySelector('.dots') // 最下面的指示器
    slideBox.prepend(slideItems[slideItems.length-1].cloneNode(true)) // 因为要做无限滚动，在最前面复制一份最后屏，在最后页复制一份第一屏
    slideBox.appendChild(slideItems[1].cloneNode(true))
    
    let len = slideItems.length - 2, index = 1

    let boxWidth = 0
    for(let i=0; i<slideItems.length; i++) { // 遍历每一项，设置宽度和高度
      let item = slideItems[i]
      item.style.width = itemW + 'px'
      item.style.height = itemH + 'px'
      boxWidth += itemW    
    }   

    slideBox.style.width = boxWidth  + 'px'  // 给图片包裹层设置宽度
    container.style.width = itemW + 'px' // 给最外层容器设置宽度

    slideBox.style.left = (index*itemW * -1) + 'px' // 设置初始时slide-box的 left值

    let btnPre = document.querySelector('.btns .pre')
    let btnNext = document.querySelector('.btns .next')
    btnPre.onclick = function() {
      if(animating) return
      if(index === 1) {
        index = len
      } else {
        index -= 1
      }      
      slide(itemW)
    }
    btnNext.onclick = function() {
      if(animating) return
      if(index === len) {
        index = 1
      } else {
        index += 1
      }      
      slide(itemW * -1)
    }
    initDots() // 初始化轮播图下面的指示器
    function initDots() {
      for(let i =1; i<=len; i++) {
        let span = document.createElement('span')
        span.setAttribute('data-index',i)
        if(index === i) {
          span.classList = 'on'
        }
        dots.appendChild(span)
        span.onclick = function() {
          if(animating) return
          let dIndex = this.getAttribute('data-index') * 1 // 注意这里要转换成数值
          let scrollPx = 0
          if(dIndex === index) {
            return
          }
          if(dIndex > index) { // 点击的是当前活动图片的后面的图片， left值应该是变小
            scrollPx = (dIndex - index) * itemW * -1
          }
          if(dIndex < index) { // 点击的是当前活动图片的前面的图片， left值应该是变大
            scrollPx = (dIndex - index) * itemW * -1
          }
          index = dIndex          
          slide(scrollPx)
        }
      }
    }
    function activeDot() { // 使指定索引的提示器高亮
      let spans = [...dots.querySelectorAll('span')]
      spans.forEach(s => s.setAttribute('class',''))
      spans[index-1].classList = 'on'
    }

    function slide(scrollPx) { // scrollPx 要滚动多少px
      if(scrollPx === 0) return
      let speed = scrollPx/(t/interval)
      let left = parseInt(slideBox.style.left)+ scrollPx // 最终的left
      animating = true
      function go() {
        // 1. 如果是向前滚(next), speed的值是负数, 当speed<0 并且当前slideBox的left值大于最终的left值
        if( (speed > 0 && parseInt(slideBox.style.left)< left) || (speed < 0 && parseInt(slideBox.style.left) > left)) {
          slideBox.style.left = parseInt(slideBox.style.left) + speed + 'px'
          setTimeout(go, interval)
        } else {
          slideBox.style.left = left + 'px'
          if(left> -1 * itemW) { // 如果是第一张，再往前滚，滚完后将left值设置成最后一张的 left
            slideBox.style.left = -1 * itemW * len + 'px'
          }
          if(left < -1 * itemW * len) { // 如果是最后一张，再往后滚，滚完后将left值设置成第一张的 left
            slideBox.style.left = -1 * itemW + 'px'
          }
          animating = false // 动画完成
        }
      }
      go()
      activeDot()
    }

    function autoPlay() { // 自动轮播
      timer = !timer && setInterval(function() {
        btnNext.onclick()
      }, 3000)
    }
    function stopPlay() {
      clearInterval(timer)
      timer = null
    }
    container.onmouseover = stopPlay  // 鼠标滑过时停止自动轮播
    container.onmouseout = autoPlay // 鼠标移开时自动轮播
    autoPlay() // js代码完成后调用一次自动轮播
  </script>
</body>
</html>